﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Net.Sockets;
using Roborally.CommonData.GlobaleTypes;
using System.Net;

namespace Roborally.Netwerklaag
{
    public class NetwerkLaag
    {
        #region Properties en Fields
        private int poort = 1337;
        private int buffergrootte = 64000;
        private bool doorgaan = true;

        private List<TcpClient> tcpClientlijst = new List<TcpClient>();

        private Thread Server_Thread;
        private TcpListener serverSocket;
        private TcpClient clientSocket;
        private IPAddress listening_adres = new IPAddress(new byte[4] { 0, 0, 0, 0 });
        public delegate void Nieuwespeler(object sender, NieuweSpelerArgs nieuwespeler);
        public delegate void OntvangBericht(object sender, BinnenkomendBericht binnenkomendbericht);
        public delegate void DisconnectClient(object sender, DisconnectClientX client);
        public delegate void JoinKamer(object sender, JoinKamerClientX client);
        public event Nieuwespeler nieuwespeler;
        public event OntvangBericht ontvangbericht;
        public event DisconnectClient disconnectclient;
        public event JoinKamer joinkamer;
        #endregion

        /// <summary>
        /// Start het luisteren op de poort in een aparte thread
        /// </summary>
        public void Start_Server()
        {
            Server_Thread = new Thread(Start_Listen);
            Server_Thread.Start();
        }

        private void Start_Listen()
        {
            serverSocket = new TcpListener(listening_adres, poort);
            clientSocket = default(TcpClient);

            serverSocket.Start();
            int counter = 0;
            while (doorgaan)
            {
                clientSocket = serverSocket.AcceptTcpClient();

                byte[] bytesFrom = new byte[buffergrootte];

                string dataFromClient = null;

                NetworkStream networkStream = clientSocket.GetStream();
                //networkStream.Read(bytesFrom, 0, (int)clientSocket.ReceiveBufferSize);
                networkStream.Read(bytesFrom, 0, buffergrootte);
                dataFromClient = System.Text.Encoding.ASCII.GetString(bytesFrom);
                int readIndex = dataFromClient.IndexOf('$');
                
                if(readIndex < 1)
                    continue;
                dataFromClient = dataFromClient.Substring(0, readIndex);

                tcpClientlijst.Add(clientSocket);

                handleClient client = new handleClient();
                //subscribe to the listening event
                client.nieuwbericht += new handleClient.OntvangBericht(client_nieuwbericht);
                client.disconnectclient += new handleClient.DisconnectClient(client_disconnectclient);

                //FIAAAAAH NEW PLAYAH EVENT!!!!!!!
                nieuwespeler(this, new NieuweSpelerArgs(dataFromClient, clientSocket));
                client.startClient(clientSocket);

                counter++;
            }
        }

        private void client_disconnectclient(object sender, DisconnectClientX client)
        {
            disconnectclient(this, client);
        }

        /// <summary>
        /// Verbreekt de verbinding met een client
        /// </summary>
        /// <param name="tcpClient">De client die de verbinding verbreekt</param>
        /// <param name="naam">De naam van de client die de verbinding verbreekt</param>
        public void Disconnect(TcpClient tcpClient, string naam)
        {
            tcpClient.Close();
        }

        private void client_nieuwbericht(object sender, BinnenkomendBericht binnenkomendbericht)
        {
            ontvangbericht(this, binnenkomendbericht);
        }

        /// <summary>
        /// Stopt de hele server
        /// </summary>
        public void Stop_Server()
        {
            disconnectclient(this, new DisconnectClientX(new TcpClient(), true));
            Server_Thread.Abort();
            doorgaan = false;
            serverSocket.Stop();
        }

        /// <summary>
        /// Verstuurt data naar een client
        /// </summary>
        /// <param name="msg">De data</param>
        /// <param name="tcpClient">De client die het ontvangen moet</param>
        /// <returns></returns>
        public bool Stuur_Bericht(string msg, TcpClient tcpClient)
        {
            try
            {
                if (tcpClient.Connected)
                {
                    Thread.Sleep(100);
                    TcpClient broadcastSocket;
                    broadcastSocket = tcpClient;
                    NetworkStream broadcastStream = broadcastSocket.GetStream();
                    Byte[] broadcastBytes = null;
                    broadcastBytes = Encoding.ASCII.GetBytes(msg + "$");
                    broadcastStream.Write(broadcastBytes, 0, broadcastBytes.Length);
                    broadcastStream.Flush();
                    return true;
                }
                else
                {
                    throw new Exception("Connection isn't connected.");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                disconnectclient(this, new DisconnectClientX(tcpClient));
                return false;
            }
        }
    }
}
